package com.free.utils;

import com.free.exception.SystemException;
import jdk.internal.dynalink.beans.StaticClass;
import org.apache.commons.lang3.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * <p>
 * 功能概述:
 * </p>
 * <p>
 * 功能详述:
 * </p>
 */
public class PropertyParseUtils {
    /*========================================================================*
     *                         Public Fields (公共属性)
     *========================================================================*/

    /*========================================================================*
     *                         Private Fields (私有属性)
     *========================================================================*/

    /*========================================================================*
     *                         Construct Methods (构造方法)
     *========================================================================*/

    /*========================================================================*
     *                         Public Methods (公有方法)
     *========================================================================*/

    public static <T,K> K get(T targetObject, String propertyNm, K defVal) throws SystemException {
        try{
            Method method = getMethodInfo(targetObject, propertyNm, false);
            Object objKeyVal = method.invoke(targetObject);
            if(objKeyVal == null){
                return defVal;
            }else{
                return (K)objKeyVal;
            }
        }
        catch (SystemException ex){
            throw ex;
        }
        catch (Exception ex){
            throw new  SystemException("" , "Class '"
                    + targetObject.getClass().getName()
                    + "' doesn't contain a property '"
                    + propertyNm
                    + "'");
        }
    }

    public static <T,K> void set(T targetObject, String propertyNm, K val, K defVal) throws SystemException {
        try{
            Method method = getMethodInfo(targetObject, propertyNm, true);
            K objVal = val == null?defVal:val;
            method.invoke(targetObject,objVal);
        }
        catch (SystemException ex){
            throw ex;
        }
        catch (Exception ex){
            throw new  SystemException("" , "Class '"
                    + targetObject.getClass().getName()
                    + "' doesn't contain a property '"
                    + propertyNm
                    + "'");
        }
    }

    public static <K> K getWithDef(Object val, K defval) throws SystemException {
        if(defval == null){
            throw new SystemException("默认值不能为空");
        }
        if(val == null){
            return defval;
        }
        if(isBaseDataType(defval.getClass())) {
            try {
                Method method = defval.getClass().getMethod("valueOf", String.class);
                defval = (K)method.invoke(defval, val.toString());
            } catch (NoSuchMethodException e) {
                throw new SystemException("PropertyParseUtils.convertTo 获得方法失败", e);
            } catch (Exception e) {
                throw new SystemException("PropertyParseUtils.convertTo 获得方法失败", e);
            }
        }else{
            return (K)val;
        }
        return defval;
    }


    /*========================================================================*
     *                         Private Methods (私有方法)
     *========================================================================*/


    private static boolean isBaseDataType(Class clazz){
        return
            (
                clazz.equals(String.class) ||
                clazz.equals(Integer.class)||
                clazz.equals(Byte.class) ||
                clazz.equals(Long.class) ||
                clazz.equals(Double.class) ||
                clazz.equals(Float.class) ||
                clazz.equals(Character.class) ||
                clazz.equals(Short.class)
            );
    }

    private static <T>  Method getMethodInfo(T targetObject, String propertyName, Boolean isRead) throws SystemException
    {

        Method method = null;
        try {
            BeanInfo targetClassInfo = Introspector.getBeanInfo(targetObject.getClass());
            for (PropertyDescriptor descriptor : targetClassInfo.getPropertyDescriptors()) {
                if(descriptor.getName().equals(propertyName)){
                    if(isRead){
                        method = descriptor.getReadMethod();
                    }else{
                        method = descriptor.getWriteMethod();
                    }
                    break;
                }
            }
        } catch (IntrospectionException e) {
            throw new SystemException("" , e);
        }
        if(method == null) {
            throw new SystemException("", "Class '"
                    + targetObject.getClass().getName()
                    + "' doesn't contain a property '"
                    + propertyName
                    + "'");

        }
        return method;
    }

}
